# checktools/iOS_check.py
import subprocess
import platform
import re
import os
import locale
import textwrap
from functools import lru_cache
from pathlib import Path

# -----------------------------------------------------------
# 全局配置与通用工具
# -----------------------------------------------------------

WSL_DISTRO_NAME = "Ubuntu-22.04"
SYSTEM_ENCODING = locale.getpreferredencoding(False)


def _clean_output(text: str) -> str:
    """清理 subprocess 输出中的 ANSI 转义字符和控制字符。"""
    ansi_escape = re.compile(r'(\x9B|\x1B\[)[0-?]*[ -/]*[@-~]')
    cleaned = ansi_escape.sub('', text)
    return re.sub(r'[\x00-\x1F\x7F-\x9F]', '', cleaned).strip()


def _find_and_get_wsl_distro() -> str:
    """自动检测并返回一个合适的 WSL 发行版名称。"""
    global WSL_DISTRO_NAME
    print("[*] 正在自动检测可用的 WSL 发行版...")
    try:
        proc = subprocess.run(
            ["wsl", "--list", "--quiet"],
            capture_output=True, check=True, timeout=10,
            encoding='utf-16-le', errors='ignore'
        )
        installed_distros = [line.strip() for line in proc.stdout.lstrip('\ufeff').splitlines() if line.strip()]

        if not installed_distros:
            raise RuntimeError(
                f"未找到任何已安装的 WSL 发行版。\n    - 请在管理员 PowerShell 中运行: wsl --install -d {WSL_DISTRO_NAME}")

        if WSL_DISTRO_NAME in installed_distros:
            print(f"✅ 已确认使用发行版: {WSL_DISTRO_NAME}")
            return WSL_DISTRO_NAME

        preferred_order = ["Ubuntu", "Ubuntu-24.04"]
        for preferred in preferred_order:
            if preferred in installed_distros:
                print(f"✅ 自动检测到并选用发行版: {preferred}")
                return preferred

        if len(installed_distros) == 1:
            distro = installed_distros[0]
            print(f"⚠️ 未找到首选发行版，将使用检测到的唯一发行版: {distro}")
            return distro

        raise RuntimeError(
            f"找到多个 WSL 发行版，但无法确定使用哪一个。\n"
            f"    已安装: {', '.join(installed_distros)}\n"
            f"    请打开此脚本，将顶部的 `WSL_DISTRO_NAME` 变量修改为您希望使用的名称。"
        )

    except FileNotFoundError:
        raise RuntimeError("❌ 'wsl.exe' not found. 请在 Windows 功能中启用“适用于 Linux 的 Windows 子系统”。")
    except subprocess.CalledProcessError as e:
        raise RuntimeError(f"执行 `wsl --list` 失败: {e.stderr or e.stdout}")
    except Exception as e:
        raise RuntimeError(f"检测 WSL 发行版时发生未知错误: {e}")


@lru_cache(maxsize=1)
def _wsl_cached_multi_check(distro_name: str) -> dict[str, tuple[int, str]]:
    """以指定 WSL 发行版的用户身份，缓存化地检查多个关键命令是否存在。"""
    try:
        proc = subprocess.run(
            ["wsl", "-d", distro_name, "--", "bash", "-ic", "echo $HOME"],
            capture_output=True, text=True, check=True,
            encoding=SYSTEM_ENCODING, errors='ignore'
        )
        wsl_home_str = proc.stdout.strip()
    except Exception as e:
        raise RuntimeError(f"致命错误：无法获取 WSL 用户 ({distro_name}) 的家目录。\n   原始错误: {e}")

    commands = {
        "swift": "command -v swift",
        "usbmuxd": "command -v usbmuxd",
        "xtool": f"command -v {wsl_home_str}/toolkit/bin/xtool",
    }
    results = {}
    for name, cmd in commands.items():
        proc = subprocess.run(
            ["wsl", "-d", distro_name, "--", "bash", "-ic", cmd],
            capture_output=True, text=True,
            encoding=SYSTEM_ENCODING, errors='ignore'
        )
        results[name] = (proc.returncode, proc.stdout.strip())
    return results


def _ensure_swift_xtool_in_wsl(distro_name: str) -> None:
    """核心函数：检查并以原子方式安装所有缺失的工具。"""
    _wsl_cached_multi_check.cache_clear()
    cached = _wsl_cached_multi_check(distro_name)
    needs_install = not all(v[0] == 0 and v[1] for v in cached.values())

    if not needs_install:
        print("✅ 所有 WSL 工具均已安装，跳过安装流程。")
        return

    needs_sudo = cached["usbmuxd"][0] != 0 or cached["swift"][0] != 0
    if needs_sudo:
        print("\n[*] 注意：后续安装过程可能需要您在终端中输入 WSL 用户的 sudo 密码。")

    print("\n[*] 检测到部分工具未安装，开始构建并执行安装任务...")

    proc = subprocess.run(
        ["wsl", "-d", distro_name, "--", "bash", "-ic", "echo $HOME"],
        capture_output=True, text=True, check=True, encoding=SYSTEM_ENCODING, errors='ignore'
    )
    wsl_home_str = proc.stdout.strip()

    install_commands = []
    path_line = f'export PATH={wsl_home_str}/toolkit/bin:$PATH'
    install_commands.append(textwrap.dedent(f"""
        if ! grep -qxF '{path_line}' {wsl_home_str}/.bashrc; then
          echo -e '\n{path_line}\n' >> {wsl_home_str}/.bashrc
          echo "✅ .bashrc PATH updated."
        fi
    """))

    if cached["swift"][0] != 0:
        install_commands.append(textwrap.dedent(f"""
            echo -e "\\n[TASK] 开始安装 Swift..."
            cd "{wsl_home_str}"

            # 【重要修复】彻底清理旧的 swiftly 配置文件，避免损坏的配置导致 'invalid toolchain selector' 错误
            if [ -d "{wsl_home_str}/.local/share/swiftly" ]; then
                echo "[*] Removing previous swiftly configuration..."
                rm -rf "{wsl_home_str}/.local/share/swiftly"
            fi

            if [ -f "swiftly-*.tar.gz" ]; then rm -f "swiftly-*.tar.gz"; fi
            curl -fLJO "https://download.swift.org/swiftly/linux/swiftly-$(uname -m).tar.gz"
            tar zxf "swiftly-$(uname -m).tar.gz"

            ./swiftly init --quiet-shell-followup --assume-yes

            # 确保 Swift 环境变量在当前脚本会话中生效
            . "{wsl_home_str}/.local/share/swiftly/env.sh"
            hash -r

            echo "✅ Swift 安装完成。"
        """))

    if cached["usbmuxd"][0] != 0:
        install_commands.append(textwrap.dedent("""
            echo -e "\\n[TASK] 开始安装 usbmuxd..."
            sudo apt-get update
            sudo apt-get install -y usbmuxd libimobiledevice-utils
            echo "✅ usbmuxd 安装完成。"
        """))

    if cached["xtool"][0] != 0:
        xtool_wsl_path = f"{wsl_home_str}/toolkit/bin/xtool"
        install_commands.append(textwrap.dedent(f"""
            echo -e "\\n[TASK] 开始安装 xtool..."
            mkdir -p "{wsl_home_str}/toolkit/bin"
            curl -L "https://github.com/tinkerbells/xtool/releases/latest/download/xtool-$(uname -m).AppImage" -o "{xtool_wsl_path}"
            chmod +x "{xtool_wsl_path}"
            echo "✅ xtool 安装完成。"
        """))

    if install_commands:
        full_script = "set -e\n" + "\n".join(install_commands)
        print("\n[*] 即将以原子方式执行安装任务，请耐心等待...")
        try:
            process = subprocess.run(
                ["wsl", "-d", distro_name, "--", "bash", "-ec", full_script],
                check=True,
                encoding=SYSTEM_ENCODING, errors='ignore'
            )
        except subprocess.CalledProcessError as e:
            raise RuntimeError(
                f"自动化安装脚本执行失败，返回码: {e.returncode}。\n   请检查日志输出。如果提示密码错误，请确认密码输入正确。")
        except Exception as e:
            raise RuntimeError(f"执行 WSL 安装脚本时发生未知错误: {e}")

        _wsl_cached_multi_check.cache_clear()
        print("\n✅ 安装流程执行完毕。")


def get_full_check_results():
    """程序入口：根据操作系统分发检查任务。"""
    current_os = platform.system()
    results = [f"--- Detected OS: {current_os} ---"]
    if current_os == "Windows":
        results.extend(_get_windows_check_results())
    elif current_os == "Darwin":
        results.extend(_get_macos_check_results())
    else:
        results.append("[!] Unsupported OS, abort.")
    return results


def _get_windows_check_results():
    """Windows 平台的完整检查流程。"""
    results = ["--- Windows / WSL Environment Check ---"]
    try:
        distro_name = _find_and_get_wsl_distro()
        subprocess.run(
            ["wsl", "-d", distro_name, "--", "true"],
            check=True, capture_output=True
        )
        results.append(f"✅ WSL & {distro_name} is running.")
    except (FileNotFoundError, RuntimeError, subprocess.CalledProcessError) as e:
        error_message = str(e)
        if "The Windows Subsystem for Linux instance has terminated." in error_message:
            results.append(f"❌ WSL 发行版 '{WSL_DISTRO_NAME}' 未在运行。")
            results.append(f"    - 请尝试在 PowerShell 中运行 'wsl -d {WSL_DISTRO_NAME}' 来启动它。")
        else:
            results.append(f"❌ {error_message}")
        return results
    except Exception as e:
        results.append(f"\n❌ 发生意外错误: {e}")
        return results

    try:
        _ensure_swift_xtool_in_wsl(distro_name)
    except RuntimeError as e:
        results.append(f"\n❌ 操作中止: {e}")
        return results

    results.append("\n--- Final Status Report ---")
    _wsl_cached_multi_check.cache_clear()
    cached = _wsl_cached_multi_check(distro_name)
    all_ready = True
    for key, name in [("swift", "Swift"), ("usbmuxd", "usbmuxd"), ("xtool", "xtool")]:
        code, out = cached[key]
        if code == 0 and out:
            results.append(f"✅ {name: <10} is ready. (Path: {out})")
        else:
            results.append(f"❌ {name: <10} is NOT ready.")
            all_ready = False

    if all_ready:
        results.append("\n🎉 恭喜！所有 WSL 工具均已正确配置！")

    xip_path = Path.home() / "xcode" / "Xcode_16.3.xip"
    results.append("\n--- Ancillary File Check ---")
    results.append(f"[*] 正在检查 Xcode 镜像文件...")
    if xip_path.exists():
        results.append(f"✅ Xcode_16.3.xip found at: {xip_path}")
    else:
        results.append(f"⚠️ Xcode_16.3.xip not found at: {xip_path}")

    return results


def _get_macos_check_results():
    """macOS 平台的检查流程。"""
    results = ["--- macOS Environment Check ---"]
    results.extend(_check_macos_tool("Xcode Command Line Tools", ["xcode-select", "-p"]))
    results.extend(_check_macos_tool("CocoaPods", ["pod", "--version"]))
    results.extend(_check_macos_tool("libimobiledevice", ["idevice_id", "-l"]))
    return results


def _check_macos_tool(tool_name: str, cmd: list):
    """在 macOS 上检查单个工具的辅助函数。"""
    results = [f"[*] Checking {tool_name} ..."]
    try:
        r = subprocess.run(
            cmd, capture_output=True, text=True,
            encoding=SYSTEM_ENCODING, errors='ignore',
            env={"LANG": "en_US.UTF-8"}, timeout=10
        )
        out = _clean_output(r.stdout or r.stderr or "")
        if r.returncode == 0 and out:
            results.append(f"✅ {tool_name} ready.")
            results.append(f"    - {out.splitlines()[0]}")
        else:
            results.append(f"❌ {tool_name} missing.")
            if out: results.append(f"    - {out}")
    except FileNotFoundError:
        results.append(f"❌ Command '{cmd[0]}' not found.")
    except Exception as e:
        results.append(f"❌ {tool_name} error: {e}")
    return results


def get_connected_ios_devices():
    """检测通过 USB 连接的 iOS 设备 (仅限 macOS)。"""
    if platform.system() != "Darwin":
        return True, ["Note: iOS device detection only works on macOS."]
    try:
        r = subprocess.run(
            ["idevice_id", "-l"], capture_output=True, text=True, check=True,
            encoding=SYSTEM_ENCODING, errors='ignore', env={"LANG": "en_US.UTF-8"}
        )
        devices = _clean_output(r.stdout).splitlines()
        return True, devices or ["No iOS devices connected."]
    except FileNotFoundError:
        return False, ["Error: 'idevice_id' not found. Please run: brew install libimobiledevice"]
    except subprocess.CalledProcessError:
        return False, ["Error: 'libimobiledevice' is not working. Try: brew reinstall libimobiledevice"]
    except Exception as e:
        return False, [f"Error: {e}"]